using System;
using System.Collections.Generic;
using System.Linq;

namespace MT5Trade.Models
{
    /// <summary>
    /// Sobol敏感性分析器 - 实现文档9.2.2节参数敏感性权重要求
    /// 使用Sobol方法进行全局敏感性分析，计算各参数对输出的影响程度
    /// 基于方差分解理论：V(Y) = ∑V_i + ∑V_ij + ... + V_12...k
    /// </summary>
    public class SobolSensitivityAnalyzer
    {
        #region 常量定义 - 基于文档9.2.2节敏感性指数

        /// <summary>
        /// 采样数量（Sobol序列需要2^n个样本）
        /// </summary>
        public const int BASE_SAMPLE_SIZE = 1024; // 2^10

        /// <summary>
        /// 参数维度
        /// </summary>
        public const int PARAMETER_DIMENSION = 5;

        /// <summary>
        /// 收敛阈值
        /// </summary>
        public const double CONVERGENCE_THRESHOLD = 0.001;

        /// <summary>
        /// 最大迭代次数
        /// </summary>
        public const int MAX_ITERATIONS = 100;

        /// <summary>
        /// 参数名称（用于报告）
        /// </summary>
        public static readonly string[] PARAMETER_NAMES = new string[]
        {
            "PositionSize",    // 仓位大小
            "StopLoss",        // 止损位置
            "Leverage",        // 杠杆比例
            "GapRatio",        // 敞口比例
            "RetryCount"       // 重试次数
        };

        /// <summary>
        /// 文档中定义的敏感性指数（用于验证）
        /// </summary>
        public static readonly double[] DOCUMENTED_INDICES = new double[]
        {
            0.387,  // 仓位大小敏感性
            0.243,  // 止损位置敏感性
            0.189,  // 杠杆比例敏感性
            0.156,  // 敞口比例敏感性
            0.098   // 重试次数敏感性
        };

        #endregion

        #region 私有字段

        private readonly IRandomProvider _randomProvider;
        private readonly Dictionary<string, double> _firstOrderIndices;
        private readonly Dictionary<string, double> _totalOrderIndices;
        private readonly Dictionary<string, List<double>> _convergenceHistory;
        private double[,] _sobolSequence;
        private bool _isAnalysisComplete;

        #endregion

        #region 构造函数

        /// <summary>
        /// 初始化Sobol敏感性分析器
        /// </summary>
        /// <param name="randomProvider">随机数提供器（可选）</param>
        public SobolSensitivityAnalyzer(IRandomProvider randomProvider = null)
        {
            _randomProvider = randomProvider ??
                DeterministicRandomProvider.CreateForOptimization($"Sobol_{DateTime.Today:yyyyMMdd}");

            _firstOrderIndices = new Dictionary<string, double>();
            _totalOrderIndices = new Dictionary<string, double>();
            _convergenceHistory = new Dictionary<string, List<double>>();
            _isAnalysisComplete = false;

            // 初始化参数索引
            for (int i = 0; i < PARAMETER_NAMES.Length; i++)
            {
                _firstOrderIndices[PARAMETER_NAMES[i]] = 0.0;
                _totalOrderIndices[PARAMETER_NAMES[i]] = 0.0;
                _convergenceHistory[PARAMETER_NAMES[i]] = new List<double>();
            }
        }

        #endregion

        #region 核心Sobol分析方法

        /// <summary>
        /// 执行全局敏感性分析
        /// 基于Saltelli的改进Sobol方法，需要N(2k+2)次模型评估
        /// </summary>
        /// <param name="modelFunction">模型函数：输入参数向量，输出标量响应</param>
        /// <param name="parameterBounds">参数边界：[min, max]对</param>
        /// <returns>Sobol分析结果</returns>
        public SobolAnalysisResult PerformGlobalSensitivityAnalysis(
            Func<double[], double> modelFunction,
            ParameterBounds[] parameterBounds)
        {
            if (modelFunction == null)
                throw new ArgumentNullException(nameof(modelFunction));

            if (parameterBounds == null || parameterBounds.Length != PARAMETER_DIMENSION)
                throw new ArgumentException($"需要{PARAMETER_DIMENSION}个参数边界", nameof(parameterBounds));

            var startTime = DateTime.Now;
            int k = PARAMETER_DIMENSION;
            int n = BASE_SAMPLE_SIZE;

            // 步骤1：生成Sobol序列样本矩阵
            var (matrixA, matrixB) = GenerateSobolMatrices(n, k, parameterBounds);

            // 步骤2：构建重组矩阵AB_i（第i列来自B，其他列来自A）
            var matricesAB = new List<double[,]>();
            for (int i = 0; i < k; i++)
            {
                matricesAB.Add(CreateRecombinedMatrix(matrixA, matrixB, i));
            }

            // 步骤3：评估模型响应
            var yA = EvaluateModel(modelFunction, matrixA);
            var yB = EvaluateModel(modelFunction, matrixB);
            var yAB = new List<double[]>();

            foreach (var matrixAB in matricesAB)
            {
                yAB.Add(EvaluateModel(modelFunction, matrixAB));
            }

            // 步骤4：计算Sobol指数
            CalculateSobolIndices(yA, yB, yAB, n, k);

            // 步骤5：验证指数和约束
            ValidateIndices();

            // 步骤6：计算收敛性指标
            double convergenceMetric = CalculateConvergenceMetric();

            _isAnalysisComplete = true;

            // 构建并返回结果
            return new SobolAnalysisResult
            {
                FirstOrderIndices = new Dictionary<string, double>(_firstOrderIndices),
                TotalOrderIndices = new Dictionary<string, double>(_totalOrderIndices),
                InteractionEffects = CalculateInteractionEffects(),
                ConvergenceMetric = convergenceMetric,
                SampleSize = n,
                ModelEvaluations = n * (2 * k + 2),
                ComputationTime = DateTime.Now - startTime,
                IsConverged = convergenceMetric < CONVERGENCE_THRESHOLD,
                ValidationPassed = ValidateAgainstDocumented()
            };
        }

        /// <summary>
        /// 计算Sobol指数（Saltelli方法）
        /// S_i = V(E(Y|X_i)) / V(Y)
        /// ST_i = 1 - V(E(Y|X_~i)) / V(Y)
        /// </summary>
        private void CalculateSobolIndices(double[] yA, double[] yB, List<double[]> yAB, int n, int k)
        {
            // 计算均值
            double meanA = yA.Average();
            double meanB = yB.Average();
            double overallMean = (meanA + meanB) / 2.0;

            // 计算总方差
            double totalVariance = 0.0;
            for (int j = 0; j < n; j++)
            {
                totalVariance += Math.Pow(yA[j] - overallMean, 2);
                totalVariance += Math.Pow(yB[j] - overallMean, 2);
            }
            totalVariance /= (2.0 * n - 1);

            if (totalVariance < 1e-10)
            {
                throw new InvalidOperationException("总方差过小，无法计算Sobol指数");
            }

            // 计算一阶和总阶Sobol指数
            for (int i = 0; i < k; i++)
            {
                double vi = 0.0;  // 一阶效应
                double vti = 0.0; // 总效应

                for (int j = 0; j < n; j++)
                {
                    // 一阶指数：S_i = V(E(Y|X_i)) / V(Y)
                    // 使用Jansen估计器
                    vi += yB[j] * (yAB[i][j] - yA[j]);

                    // 总阶指数：ST_i = E(V(Y|X_~i)) / V(Y)
                    // 使用Sobol估计器
                    vti += Math.Pow(yA[j] - yAB[i][j], 2);
                }

                vi /= n;
                vti /= (2.0 * n);

                // 归一化得到指数
                double firstOrderIndex = vi / totalVariance;
                double totalOrderIndex = vti / totalVariance;

                // 确保指数在合理范围内
                firstOrderIndex = Math.Max(0.0, Math.Min(1.0, firstOrderIndex));
                totalOrderIndex = Math.Max(0.0, Math.Min(1.0, totalOrderIndex));

                // 存储结果
                _firstOrderIndices[PARAMETER_NAMES[i]] = firstOrderIndex;
                _totalOrderIndices[PARAMETER_NAMES[i]] = totalOrderIndex;

                // 记录收敛历史
                _convergenceHistory[PARAMETER_NAMES[i]].Add(firstOrderIndex);
            }
        }

        #endregion

        #region Sobol序列生成

        /// <summary>
        /// 生成Sobol序列样本矩阵
        /// </summary>
        private (double[,], double[,]) GenerateSobolMatrices(int n, int k, ParameterBounds[] bounds)
        {
            // 生成准随机Sobol序列
            _sobolSequence = GenerateSobolSequence(n * 2, k);

            // 创建两个独立的样本矩阵
            double[,] matrixA = new double[n, k];
            double[,] matrixB = new double[n, k];

            // 填充矩阵A（前n个样本）
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < k; j++)
                {
                    double unitValue = _sobolSequence[i, j];
                    matrixA[i, j] = bounds[j].Min + unitValue * (bounds[j].Max - bounds[j].Min);
                }
            }

            // 填充矩阵B（后n个样本）
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < k; j++)
                {
                    double unitValue = _sobolSequence[n + i, j];
                    matrixB[i, j] = bounds[j].Min + unitValue * (bounds[j].Max - bounds[j].Min);
                }
            }

            return (matrixA, matrixB);
        }

        /// <summary>
        /// 生成Sobol准随机序列
        /// 使用灰码和方向数生成低差异序列
        /// </summary>
        private double[,] GenerateSobolSequence(int n, int k)
        {
            double[,] sequence = new double[n, k];

            // 初始化方向数（使用Joe-Kuo方向数的简化版本）
            uint[,] v = InitializeDirectionNumbers(k);

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < k; j++)
                {
                    // 使用确定性随机数生成器
                    // 这里简化为使用确定性伪随机数，实际应用中应使用真正的Sobol序列
                    double deterministicValue = _randomProvider.NextDouble();

                    // Van der Corput序列（一维Sobol序列的特例）
                    sequence[i, j] = VanDerCorputSequence(i + 1, GetPrime(j + 1));

                    // 添加小的扰动以避免完全相同的值
                    sequence[i, j] = (sequence[i, j] + deterministicValue * 0.01) % 1.0;
                }
            }

            return sequence;
        }

        /// <summary>
        /// Van der Corput序列生成（用于简化的Sobol序列）
        /// </summary>
        private double VanDerCorputSequence(int n, int baseNum)
        {
            double result = 0.0;
            double f = 1.0 / baseNum;
            int i = n;

            while (i > 0)
            {
                result += f * (i % baseNum);
                i /= baseNum;
                f /= baseNum;
            }

            return result;
        }

        /// <summary>
        /// 获取第n个质数
        /// </summary>
        private int GetPrime(int n)
        {
            int[] primes = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 };
            return n <= primes.Length ? primes[n - 1] : 31;
        }

        /// <summary>
        /// 初始化Sobol序列的方向数
        /// </summary>
        private uint[,] InitializeDirectionNumbers(int dimension)
        {
            // 简化的方向数初始化
            uint[,] v = new uint[dimension, 32];

            for (int d = 0; d < dimension; d++)
            {
                for (int i = 0; i < 32; i++)
                {
                    v[d, i] = (uint)(1 << (31 - i));
                }
            }

            return v;
        }

        #endregion

        #region 辅助方法

        /// <summary>
        /// 创建重组矩阵AB_i
        /// </summary>
        private double[,] CreateRecombinedMatrix(double[,] matrixA, double[,] matrixB, int columnIndex)
        {
            int n = matrixA.GetLength(0);
            int k = matrixA.GetLength(1);
            double[,] matrixAB = new double[n, k];

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < k; j++)
                {
                    if (j == columnIndex)
                    {
                        matrixAB[i, j] = matrixB[i, j]; // 第columnIndex列来自B
                    }
                    else
                    {
                        matrixAB[i, j] = matrixA[i, j]; // 其他列来自A
                    }
                }
            }

            return matrixAB;
        }

        /// <summary>
        /// 评估模型响应
        /// </summary>
        private double[] EvaluateModel(Func<double[], double> modelFunction, double[,] inputMatrix)
        {
            int n = inputMatrix.GetLength(0);
            double[] responses = new double[n];

            for (int i = 0; i < n; i++)
            {
                double[] parameters = new double[PARAMETER_DIMENSION];
                for (int j = 0; j < PARAMETER_DIMENSION; j++)
                {
                    parameters[j] = inputMatrix[i, j];
                }

                responses[i] = modelFunction(parameters);
            }

            return responses;
        }

        /// <summary>
        /// 计算交互效应
        /// </summary>
        private Dictionary<string, double> CalculateInteractionEffects()
        {
            var interactions = new Dictionary<string, double>();

            for (int i = 0; i < PARAMETER_NAMES.Length; i++)
            {
                for (int j = i + 1; j < PARAMETER_NAMES.Length; j++)
                {
                    string key = $"{PARAMETER_NAMES[i]}-{PARAMETER_NAMES[j]}";

                    // 交互效应 = 总效应 - 一阶效应
                    double interaction =
                        _totalOrderIndices[PARAMETER_NAMES[i]] - _firstOrderIndices[PARAMETER_NAMES[i]] +
                        _totalOrderIndices[PARAMETER_NAMES[j]] - _firstOrderIndices[PARAMETER_NAMES[j]];

                    interactions[key] = Math.Max(0, interaction / 2.0);
                }
            }

            return interactions;
        }

        /// <summary>
        /// 验证指数约束
        /// </summary>
        private void ValidateIndices()
        {
            // 验证一阶指数和 ≤ 1
            double sumFirstOrder = _firstOrderIndices.Values.Sum();
            if (sumFirstOrder > 1.0 + CONVERGENCE_THRESHOLD)
            {
                // 归一化
                foreach (var key in _firstOrderIndices.Keys.ToList())
                {
                    _firstOrderIndices[key] /= sumFirstOrder;
                }
            }

            // 验证总阶指数 ≥ 一阶指数
            foreach (var param in PARAMETER_NAMES)
            {
                if (_totalOrderIndices[param] < _firstOrderIndices[param])
                {
                    _totalOrderIndices[param] = _firstOrderIndices[param];
                }
            }
        }

        /// <summary>
        /// 计算收敛性指标
        /// </summary>
        private double CalculateConvergenceMetric()
        {
            if (_convergenceHistory.Count == 0 ||
                _convergenceHistory.Values.All(h => h.Count < 2))
            {
                return 1.0; // 未收敛
            }

            double maxChange = 0.0;

            foreach (var param in PARAMETER_NAMES)
            {
                var history = _convergenceHistory[param];
                if (history.Count >= 2)
                {
                    double lastValue = history[history.Count - 1];
                    double previousValue = history[history.Count - 2];
                    double change = Math.Abs(lastValue - previousValue);
                    maxChange = Math.Max(maxChange, change);
                }
            }

            return maxChange;
        }

        /// <summary>
        /// 验证计算结果是否与文档值接近
        /// </summary>
        private bool ValidateAgainstDocumented()
        {
            double tolerance = 0.1; // 10%误差容忍度

            for (int i = 0; i < PARAMETER_NAMES.Length; i++)
            {
                double calculated = _firstOrderIndices[PARAMETER_NAMES[i]];
                double documented = DOCUMENTED_INDICES[i];
                double relativeError = Math.Abs(calculated - documented) / documented;

                if (relativeError > tolerance)
                {
                    return false;
                }
            }

            return true;
        }

        #endregion

        #region 公共接口

        /// <summary>
        /// 获取参数优化优先级（基于敏感性指数排序）
        /// </summary>
        public List<ParameterPriority> GetOptimizationPriorities()
        {
            if (!_isAnalysisComplete)
            {
                throw new InvalidOperationException("请先执行敏感性分析");
            }

            var priorities = new List<ParameterPriority>();

            var sortedParams = _firstOrderIndices
                .OrderByDescending(kvp => kvp.Value)
                .ToList();

            for (int i = 0; i < sortedParams.Count; i++)
            {
                var param = sortedParams[i];
                priorities.Add(new ParameterPriority
                {
                    ParameterName = param.Key,
                    SensitivityIndex = param.Value,
                    Priority = i + 1,
                    OptimizationFrequency = GetOptimizationFrequency(param.Value),
                    AdjustmentStepSize = GetAdjustmentStepSize(param.Key)
                });
            }

            return priorities;
        }

        /// <summary>
        /// 根据敏感性指数确定优化频率
        /// </summary>
        private string GetOptimizationFrequency(double sensitivityIndex)
        {
            if (sensitivityIndex > 0.3)
                return "每笔交易";
            else if (sensitivityIndex > 0.2)
                return "每15分钟";
            else if (sensitivityIndex > 0.1)
                return "每小时";
            else
                return "每日";
        }

        /// <summary>
        /// 获取参数调整步长
        /// </summary>
        private double GetAdjustmentStepSize(string parameterName)
        {
            return parameterName switch
            {
                "PositionSize" => 0.01,  // 0.01手
                "StopLoss" => 0.01,       // 1%
                "Leverage" => 10.0,       // 1:10
                "GapRatio" => 0.01,       // 1%
                "RetryCount" => 1.0,      // 1次
                _ => 0.01
            };
        }

        #endregion

        #region 数据结构定义

        /// <summary>
        /// 参数边界
        /// </summary>
        public class ParameterBounds
        {
            public double Min { get; set; }
            public double Max { get; set; }
            public string Name { get; set; }
        }

        /// <summary>
        /// Sobol分析结果
        /// </summary>
        public class SobolAnalysisResult
        {
            public Dictionary<string, double> FirstOrderIndices { get; set; }
            public Dictionary<string, double> TotalOrderIndices { get; set; }
            public Dictionary<string, double> InteractionEffects { get; set; }
            public double ConvergenceMetric { get; set; }
            public int SampleSize { get; set; }
            public int ModelEvaluations { get; set; }
            public TimeSpan ComputationTime { get; set; }
            public bool IsConverged { get; set; }
            public bool ValidationPassed { get; set; }
        }

        /// <summary>
        /// 参数优先级
        /// </summary>
        public class ParameterPriority
        {
            public string ParameterName { get; set; }
            public double SensitivityIndex { get; set; }
            public int Priority { get; set; }
            public string OptimizationFrequency { get; set; }
            public double AdjustmentStepSize { get; set; }
        }

        #endregion
    }
}